// 扩展vue原有的功能：全局组件，自定义指令，挂载原型方法
// 插件
// 导出一个对象，有install函数，默认传入了app实例，app基础上扩展
// import ShopSkeleton from './shop-skeleton'
// import ShopSwiper from './shop-swiper'
// import ShopMore from './shop-more'
// import ShopBread from './shop-bread'
// import ShopBreadItem from './shop-bread-item'
import defaultImg from '@/assets/images/200.png'
import Message from './Message'

// context(目录路径，是否加载子目录，加载文件的匹配(可写正则))
const importFn = require.context('./', false, /\.vue$/)

export default {
  install (app) {
    // app上进行扩展，app提供了component directive函数
    // 挂载在原型上，则 app.config.globalProperties
    // app.component(ShopSkeleton.name, ShopSkeleton)
    // app.component(ShopSwiper.name, ShopSwiper)
    // app.component(ShopMore.name, ShopMore)
    // app.component(ShopBread.name, ShopBread)
    // app.component(ShopBreadItem.name, ShopBreadItem)
    // importFn函数中有一个key()属性，存放需要导入的所有文件路径
    // 根据keys()获取所有文件路径
    importFn.keys().forEach(path => {
      // 每个vue组件都有export default
      const component = importFn(path).default
      // 批量注册组件
      app.component(component.name, component)
    })
    // 定义指令
    defineDirective(app)
    // 定义一个原型函数
    app.config.globalProperties.$message = Message
  }
}

// 定义图片懒加载指令
const defineDirective = (app) => {
  // 1.图片懒加载指令 v-lazy
  // 原理：图片地址先存着其他地方，当图片进入可视区，才将图片地址赋值给src(操作dom)
  // 第一个参数是名字，第二个参数是配置指令
  app.directive('lazy', {
    // vue2 监听使用指令的dom是否创建好，钩子函数：inserted
    // vue3 监听使用指令的dom是否创建好，指令钩子函数和组件的一样，mounted
    // binging.value为元素v-bind绑定的值
    mounted(el, binding) {
      // 创建一个观察对象，观察当前使用指令的元素
      // 第一个参数是回调函数(参数1:被观察的元素数组(属性1:isIntersecting))，第二个参数是配置选项
      const observe = new IntersectionObserver(([{ isIntersecting }]) => {
        // 如果元素进入可视区
        if (isIntersecting) {
          // 2.停止观察
          observe.unobserve(el)
          // 3.将指令上的图片地址赋值给src binding.value是指令的值
          el.src = binding.value
          // 4.处理图片加载失败
          el.onerror = () => {
            // 加载失败时设置为默认图
            el.src = defaultImg
          }
        }
      }, {
        threshold: 0
      })
      // 1.开启观察使用指令的元素
      observe.observe(el)
    }
  })
}
